package de.tu_darmstadt.gdi1.xcom.tests.testcases.tutors;

import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;

import org.junit.Before;
import org.junit.Test;

import de.tu_darmstadt.gdi1.xcom.tests.adapters.XcomTestAdapterLevel1;

/**
 * 
 * Tests if the action-points are decreased correctly
 * 
 * @author Lukas Schwoebel
 *
 */
public class ActionPointsTest {
	
	private XcomTestAdapterLevel1 testAdapter;
	
	/**
	 * @throws java.lang.Exception
	 */
	@Before
	public void setUp() throws Exception {
		testAdapter = new XcomTestAdapterLevel1();
	}

	/**
	 * Test method for {@link de.tu_darmstadt.gdi1.xcom.tests.adapters.XcomTestAdapterLevel1#actionPointsLeft()}.
	 */
	@Test
	public final void testRotateUntilEnd() {
		testAdapter.loadLevelFromString(TestLevel.testLevel);

		int i = TestLevel.actionPoints;
		// first check if action points are 75 per default
		assertEquals("The action-points should be "+TestLevel.actionPoints+" after loading of the level", TestLevel.actionPoints, testAdapter.actionPointsLeft());
		while(i > 0) {
			// rotate, alternate rotation-direction
			// basically nearly the same test as student-testcase, but
			// different level-file
			testAdapter.rotateActivePlayer( ((i%2) == 0));
			i--;
		}
		// now check if action points are zero
		assertEquals("The action-points should be 0 after "+TestLevel.actionPoints+" rotations", 0, testAdapter.actionPointsLeft());	
	}

	/**
	 * Test method for {@link de.tu_darmstadt.gdi1.xcom.tests.adapters.XcomTestAdapterLevel1#actionPointsLeft()}.
	 */
	@Test
	public final void testWalkingCosts() {
		testAdapter.loadLevelFromString(TestLevel.testLevel);

		// first change to player 9:2 (should be active at the beginning)
		testAdapter.changeActivePlayer(9, 2);	
		
		// first check if action points are 75 per default
		assertEquals("The action-points should be "+TestLevel.actionPoints+" after loading of the level", TestLevel.actionPoints, testAdapter.actionPointsLeft());

		// test if walking for every player/human costs the same
			
		// first player, need to be rotated
		testAdapter.rotateActivePlayer(true);
		testAdapter.performActionForActivePlayer();
		assertEquals("Walking action for player (9:2) should cost 3 actionpoints", TestLevel.actionPoints-4, testAdapter.actionPointsLeft());

		// change player and rotate as well
		testAdapter.changeActivePlayer(4, 3);
		testAdapter.rotateActivePlayer(true);
		testAdapter.performActionForActivePlayer();
		assertEquals("Walking action for player (4:3) should cost 3 actionpoints", TestLevel.actionPoints-4, testAdapter.actionPointsLeft());

		// change player and rotate as well
		testAdapter.changeActivePlayer(1, 4);
		testAdapter.rotateActivePlayer(true);
		testAdapter.performActionForActivePlayer();
		assertEquals("Walking action for player (1:4) should cost 3 actionpoints", TestLevel.actionPoints-4, testAdapter.actionPointsLeft());
		
		// change player, no rotation needed
		testAdapter.changeActivePlayer(11, 4);
		testAdapter.performActionForActivePlayer();
		assertEquals("Walking action for player (11:4) should cost 3 actionpoints", TestLevel.actionPoints-3, testAdapter.actionPointsLeft());
	}

	/**
	 * Test method for {@link de.tu_darmstadt.gdi1.xcom.tests.adapters.XcomTestAdapterLevel1#actionPointsLeft()}.
	 */
	@Test
	public final void testRotationCosts() {
		testAdapter.loadLevelFromString(TestLevel.testLevel);

		// first change to player 9:2 (should be active at the beginning)
		testAdapter.changeActivePlayer(9, 2);	
		
		// first check if action points are 75 per default
		assertEquals("The action-points should be "+TestLevel.actionPoints+" after loading of the level", TestLevel.actionPoints, testAdapter.actionPointsLeft());

		// test if rotations costs 1 action point
			
		// first player, need to be rotated
		testAdapter.rotateActivePlayer(true);
		assertEquals("One Rotation action for player (9:2) should cost 1 actionpoint", TestLevel.actionPoints-1, testAdapter.actionPointsLeft());
		// rotate counter-clockwise twice
		testAdapter.rotateActivePlayer(false);
		testAdapter.rotateActivePlayer(false);
		assertEquals("Two rotation actions for player (9:2) should cost 2 actionpoints", TestLevel.actionPoints-3, testAdapter.actionPointsLeft());

		// change player and rotate as well
		testAdapter.changeActivePlayer(4, 3);
		testAdapter.rotateActivePlayer(false);
		testAdapter.rotateActivePlayer(true);
		testAdapter.rotateActivePlayer(false);
		testAdapter.rotateActivePlayer(false);	
		testAdapter.rotateActivePlayer(true);	
		assertEquals("5 rotations actions for player (4:3) should cost 5 actionpoints", TestLevel.actionPoints-5, testAdapter.actionPointsLeft());
	}	
	

	/**
	 * Test method for {@link de.tu_darmstadt.gdi1.xcom.tests.adapters.XcomTestAdapterLevel1#actionPointsLeft()}.
	 */
	@Test
	public final void testActionPointsWithChangingPlayer() {
		testAdapter.loadLevelFromString(TestLevel.testLevel);
		
		// now this test doesn't really 100% cover "actionpoints" but the (valid)
		// changing of players/humans.
		
		// the first player should be at 9:2, so check if he/it is really active at the beginning
		testAdapter.rotateActivePlayer(true);
		testAdapter.performActionForActivePlayer();
		
		// test if the right player was moved
		String expectedLevelRep1 = "" +
			"########################\n" +
			"#...#....#.......#######\n" +
			"#ZZ##.....@.###c####..##\n" +
			"##.#@....#......=..#...#\n" +
			"#@.#######.@....#ZZZZZZ#\n" +
			"c..#....##......####=###\n" +
			"#..###=#######.........c\n" +
			"#......................#\n" +
			"########################";
		String expectedLevelRep2 = "" +
			"########################\n" +
			"#...#....#.......#######\n" +
			"#ZZ##.....@.########..##\n" +
			"##.#@....#.........#...#\n" +
			"#@.#######.@....#ZZZZZZ#\n" +
			"#..#....##......####.###\n" +
			"#..###.#######.........#\n" +
			"#......................#\n" +
			"########################";
		
		String returnedLevel = testAdapter.levelRepresentationAsString();
		
		assertEquals("The first player in the list should be active per default (moved to 10:2)." +
				" Either wrong player, or the level-representation is wrong, should be: \n" + expectedLevelRep1, true,
				(returnedLevel.equals(expectedLevelRep1) || returnedLevel.equals(expectedLevelRep2)));
		
		// now player should be at 10:2, face east and have 71 actionpoints
		// change to player 10:2 and look if this is true
		// so we change to the "current" player, this should be possible(?)
		testAdapter.changeActivePlayer(10, 2);
		
		assertEquals("The first player in the list should be active per default, after changing to 10:2, he should look to east", 2, testAdapter.activePlayerLookingToDirection());
		assertEquals("The first player in the list should be active per default, after changing to 10:2, he should have 71 actionpoints", 71, testAdapter.actionPointsLeft());
		
		// now change to player 4:3
		testAdapter.changeActivePlayer(4, 3);
		// should look to north and have 75 actionpoints
		assertEquals("Player at 4:3 should look to north per default", 1, testAdapter.activePlayerLookingToDirection());
		assertEquals("Player at 4:3 should have 75 actionpoints per default", 75, testAdapter.actionPointsLeft());
		
		// now change back to 10:2
		testAdapter.changeActivePlayer(10, 2);
		// make an invalid change, no player at 13:9
		testAdapter.changeActivePlayer(13, 9);
		// should not have changed the player
		assertEquals("An invalid change was made, no player on 13:9, the player on 10:2 still should be active (looks to east)", 2, testAdapter.activePlayerLookingToDirection());
		assertEquals("An invalid change was made, no player on 13:9, the player on 10:2 still should be active (has 71 actionpoints)", 71, testAdapter.actionPointsLeft());

		
		String levelRepBeforeChange = testAdapter.levelRepresentationAsString();
		// test if an exception is thrown if an player is chosen whos respecitve coordinates are outside the gamearea
		// this is the obligatory *only to tease students*-test
		try {
			testAdapter.changeActivePlayer(13, 37);
		}
		catch (Exception e) {
			fail("If a player is chosen with coordinates outside of the gamearea, no exception should be thrown. " +
					"But as in 'real' this is not possible, failing this test is not dramatically");
		}
		assertEquals("Changing to a player that doesn't exist, should not change the gameara", levelRepBeforeChange, testAdapter.levelRepresentationAsString());
	}
}
